﻿using System;

/// <summary>
/// DZC-9R/9RE 火工品电阻测量仪 串口通信协议实现
/// 协议版本：V1.1
/// </summary>
internal static class Dzc9RProtocol
{
    #region 常量定义
    /// <summary>
    /// 一帧数据长度
    /// </summary>
    public const int FRAME_LENGTH = 8;

    /// <summary>
    /// 默认设备地址（第一台仪器）
    /// </summary>
    public const byte DEVICE_ADDR_DEFAULT = 0x01;

    /* ---------- 上位机命令（字节7） ---------- */
    /// <summary>
    /// 读 1# 通道数据（协议：0x01）
    /// </summary>
    public const byte CMD_CHANNEL_1 = 0x01;

    /// <summary>
    /// 读 2# 通道数据（协议：0x02）
    /// </summary>
    public const byte CMD_CHANNEL_2 = 0x02;

    /* ---------- 上位机被操作参数（字节5） ---------- */
    /// <summary>
    /// 双向低电阻工作模式
    /// </summary>
    public const byte PARAM_BIDIR_LOW = 0x03;

    /* ---------- 设备回传参数（字节5） ---------- */
    /// <summary>
    /// 双向电阻值
    /// </summary>
    public const byte RESP_BIDIR_LOW = 0x87;

    /// <summary>
    /// 双向电阻过量程
    /// </summary>
    public const byte RESP_OVER_RANGE = 0x85;
    #endregion

    #region 公共方法
    /// <summary>
    /// 计算并填充校验和（字节0）
    /// 校验规则：字节1~7 进行逐字节异或
    /// </summary>
    private static byte CalcChecksum(byte[] frame)
    {
        byte chk = 0;
        for (int i = 1; i < FRAME_LENGTH; i++)
            chk ^= frame[i];
        return chk;
    }

    /// <summary>
    /// 构造完整帧
    /// </summary>
    /// <param name="deviceAddress">设备地址（0x01~0xFF）</param>
    /// <param name="command">通道命令（0x01、0x02 …）</param>
    /// <param name="parameter">工作模式参数</param>
    /// <param name="data">4 字节操作数据，默认为 0</param>
    /// <returns>8 字节完整帧</returns>
    public static byte[] BuildCommand(byte deviceAddress, byte command, byte parameter, uint data = 0)
    {
        byte[] frame = new byte[FRAME_LENGTH];

        // [4][3][2][1] 四字节操作数据，低字节在前
        frame[1] = (byte)(data & 0xFF);
        frame[2] = (byte)((data >> 8) & 0xFF);
        frame[3] = (byte)((data >> 16) & 0xFF);
        frame[4] = (byte)((data >> 24) & 0xFF);

        frame[5] = parameter;      // 被操作参数
        frame[6] = deviceAddress;  // 设备地址
        frame[7] = command;        // 通道命令

        frame[0] = CalcChecksum(frame); // 校验和
        return frame;
    }

    /// <summary>
    /// 校验帧完整性
    /// </summary>
    public static bool VerifyChecksum(byte[] frame)
    {
        if (frame == null || frame.Length != FRAME_LENGTH) return false;
        return frame[0] == CalcChecksum(frame);
    }

    /// <summary>
    /// 解析双向低电阻结果
    /// </summary>
    /// <param name="frame">完整 8 字节响应帧</param>
    /// <returns>电阻值，单位 Ω</returns>
    public static double ParseBidirLowResistance(byte[] frame)
    {
        if (!VerifyChecksum(frame))
            throw new ArgumentException("帧校验失败");
        if (frame[5] == RESP_OVER_RANGE)
            throw new InvalidOperationException("双向低电阻过量程");

        uint raw = (uint)(frame[1] | (frame[2] << 8) | (frame[3] << 16) | (frame[4] << 24));
        return raw * 0.0001; // 0.1 mΩ → Ω
    }
    #endregion
}